package org.example.learn.bytebuddy.annotation;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

// 创建类 并添加 注解
public class GenerateClass {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
        // 生成含有注解的泛型实现类
        DynamicType.Unloaded dynamicType = new ByteBuddy()
                // 构造复杂类型 TypeDescription.Generic.Builder.parameterizedType(Repository.class,String.class).build()
                .subclass(TypeDescription.Generic.Builder.parameterizedType(Repository.class,String.class).build())
                .name(Repository.class.getPackage().getName().concat(".").concat("TestRepository"))
                .method(ElementMatchers.named("queryById"))
                // 拦截 并委托类
                .intercept(MethodDelegation.to(DataRepositoryInterceptor.class))
                // 设置方法注解
                .annotateMethod(AnnotationDescription.Builder.ofType(AMethod.class).define("declare","查询").define("alias","别名").build())
                // 设置类注解
                .annotateType(AnnotationDescription.Builder.ofType(AClass.class).define("classDeclare","测试").define("alias","Test").define("id",11).build())
                .make();

        // 使用反射执行方法
        Class<?> clazz = dynamicType.load(GenerateClass.class.getClassLoader()).getLoaded();
        Object val = clazz.getMethod("queryById",String.class).invoke(clazz.newInstance(),"123");
        System.out.println("反射执行结果：" + val);

        System.out.println("输出创建的类");
        // 输出创建的类
        try {
            dynamicType.saveIn(new File(GenerateClass.class.getResource("/").getPath()));
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("打印创建类上的注解信息");
        // 输出注解信息
        Class<Repository<String>> repositoryClass = (Class<Repository<String>>) Class.forName("org.example.learn.bytebuddy.annotation.TestRepository");

        //获取类注解
        AClass aClass = repositoryClass.getAnnotation(AClass.class);
        System.out.println("AClass.classDeclare：" + aClass.classDeclare());
        System.out.println("AClass.alias：" + aClass.alias());
        System.out.println("AClass.id：" + aClass.id());

        //获取方法注解
        AMethod aMethod = repositoryClass.getMethod("queryById", String.class).getAnnotation(AMethod.class);
        System.out.println("AMethod.declare：" + aMethod.declare());
        System.out.println("AMethod.alias：" + aMethod.alias());

        System.out.println("创建对应对象执行效果（有委托）：");
        Repository<String> testRepository = repositoryClass.newInstance();
        System.out.println(testRepository.queryById("Test")); // 会输出委托类的相关方法结果
    }
}
